/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.icanci.loopstack.damc.core;

import java.lang.instrument.Instrumentation;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.*;
import org.springframework.stereotype.Service;

import com.google.common.collect.Maps;

import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import cn.icanci.loopstack.damc.api.groovy.GroovyScriptRepository;
import cn.icanci.loopstack.damc.api.http.Client;
import cn.icanci.loopstack.damc.api.http.HttpClientImpl;
import cn.icanci.loopstack.damc.cache.ArgsValidateResult;
import cn.icanci.loopstack.damc.cache.DamcCenterConfigRepository;
import cn.icanci.loopstack.damc.core.dynamic.*;
import cn.icanci.loopstack.damc.core.server.RegisterServer;
import cn.icanci.loopstack.damc.core.service.DamcApplicationContextAware;
import cn.icanci.loopstack.damc.spi.model.UriConstant;
import cn.icanci.loopstack.damc.spi.model.pubsub.LoadScriptDTO;
import cn.icanci.loopstack.damc.spi.model.pubsub.LoadScriptResponseDTO;
import cn.icanci.loopstack.damc.spi.model.refresh.RefreshCell;

/**
 * Damc启动函数
 * 
 * @author icanci
 * @since 1.0 Created in 2025/05/14 18:30
 */
@Service("damcCoreStart")
public class DamcCoreStart implements ApplicationContextAware {
    /** http实例 */
    private static final Client CLIENT         = HttpClientImpl.getInstance();
    /** 注册请求地址 */
    private static final String REQ_URL_FORMAT = "http://%s:%s%s";

    private static final Logger logger         = LoggerFactory.getLogger(DamcCoreStart.class);

    public static void setInitParam(ArgsValidateResult result, Instrumentation inst) {
        // 初始化到仓储
        DynamicAgent.setInstrumentation(inst);
        DynamicAgent.setResult(result);
    }

    /**
     * Set the ApplicationContext that this object runs in.
     * Normally this call will be used to initialize the object.
     * <p>Invoked after population of normal bean properties but before an init callback such
     * as {@link InitializingBean#afterPropertiesSet()}
     * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
     * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
     * {@link MessageSourceAware}, if applicable.
     *
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws ApplicationContextException in case of context initialization errors
     * @throws BeansException              if thrown by application context methods
     * @see BeanInitializationException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        try {
            // 获取类加载器
            ClassLoader classLoader = this.getClass().getClassLoader();
            System.getProperties().put(DamcCoreConstant.APP_RUNNER_CLASS_LOADER, classLoader.getClass().getName());

            AttachTool.attachAgent();

            DamcApplicationContextAware.setContext(applicationContext);

            RegisterServer server = applicationContext.getBean(RegisterServer.class);
            server.startNettyServer();
            // 初始化缓存仓储
            loadAllScript();
            // do agent
            loadAllAgent();

        } catch (Exception e) {
            throw new BeanInitializationException(e.getMessage());
        }
    }

    private void loadAllScript() {
        // 查询数据
        String[] addresses = DamcCenterConfigRepository.getDamcCenterAddress().split(";");
        int damcCenterPort = DamcCenterConfigRepository.getDamcCenterPort();
        LoadScriptDTO loadScript = new LoadScriptDTO();
        loadScript.setAppCode(DamcCenterConfigRepository.getMockedProjectCode());
        for (String address : addresses) {
            try {
                String reqUrl = String.format(REQ_URL_FORMAT, address, damcCenterPort, UriConstant.LOAD_SCRIPT);
                Client.RpcRequest rpcRequest = new Client.RpcRequest(reqUrl, loadScript, Maps.newHashMap(), Method.POST, 3, TimeUnit.SECONDS, 0);

                String socketMessage = CLIENT.call(rpcRequest, String.class);
                logger.warn("[DamcCoreStart][loadAllScript] socketMessage:{}", socketMessage);
                LoadScriptResponseDTO response = JSONUtil.toBean(socketMessage, LoadScriptResponseDTO.class);
                List<RefreshCell> content = response.getContent();
                GroovyScriptRepository.refreshCache(content);
            } catch (Throwable ex) {
                logger.error("[TriggerThread][Run][Throwable] error message:{}", ex.getMessage());
            }
        }
    }

    private void loadAllAgent() throws Exception {
        List<RefreshCell> refreshCells = GroovyScriptRepository.getRefreshCells();
        ReTransformTriggerMBean bean = new ReTransformTrigger();
        for (RefreshCell refreshCell : refreshCells) {
            bean.reTransformClass(refreshCell);
        }
    }

}
